package com.yycx.module.order.provider.service.impl;

import com.yycx.common.constants.CommonConstants;
import com.yycx.common.mybatis.base.service.impl.BaseServiceImpl;
import com.yycx.common.base.entity.EntityMap;
import com.yycx.common.mybatis.model.ResultBody;
import com.yycx.common.mybatis.query.CriteriaDelete;
import com.yycx.common.mybatis.query.CriteriaQuery;
import com.yycx.common.mybatis.query.CriteriaSave;
import com.yycx.common.mybatis.query.CriteriaUpdate;
import com.yycx.common.security.OpenHelper;
import com.yycx.common.utils.ApiAssert;
import com.yycx.common.base.utils.FlymeUtils;
import com.yycx.module.marketing.provider.service.CouponUserService;
import com.yycx.module.order.client.entity.OrderDetails;
import com.yycx.module.order.client.entity.OrderShopcart;
import com.yycx.module.order.provider.mapper.OrderShopcartMapper;
import com.yycx.module.order.provider.service.OrderShopcartService;
import com.yycx.module.product.client.entity.ProdProduct;
import com.yycx.module.product.client.entity.ProdShop;
import com.yycx.module.product.client.entity.ProdSku;
import com.yycx.module.product.provider.service.ProdAftersaleService;
import com.yycx.module.product.provider.service.ProdProductService;
import com.yycx.module.product.provider.service.ProdSkuService;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.rowset.serial.SerialClob;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 购物车接口实现类
 *
 * @author flyme
 * @date 2019-12-01
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class OrderShopcartServiceImpl extends BaseServiceImpl<OrderShopcartMapper, OrderShopcart> implements OrderShopcartService {


    @Autowired
    private ProdSkuService skuService;

    @Autowired
    private ProdProductService productService;

    @Autowired
    private CouponUserService couponUserService;

    @Autowired
    private ProdAftersaleService aftersaleService;

    /**
     * 我的购车列表条件设置
     *
     * @param cq
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforeListEntityMap(CriteriaQuery<OrderShopcart> cq, OrderShopcart orderShopcart, EntityMap requestMap) {
        Long userId = OpenHelper.getUserId();
        cq.select(OrderShopcart.class, "*");
        cq.eq(OrderShopcart.class, "userId", userId);
        cq.select(ProdSku.class, "skuId", "title", "skuTitle", "images", "indexes", "price", "num", "productNo");
        cq.select(ProdShop.class, "shopName", "companyId");
        cq.select(ProdProduct.class, "coverImage");
        cq.createJoin(ProdSku.class);
        cq.createJoin(ProdShop.class);
        cq.createJoin(ProdProduct.class);
        return ResultBody.ok();
    }

    /**
     * 我的购物车列表数据扩展
     *
     * @param cq
     * @param data
     * @param resultBody
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody afterListEntityMap(CriteriaQuery<OrderShopcart> cq, List<EntityMap> data, ResultBody resultBody) {
        EntityMap result = new EntityMap();
        Long userId = OpenHelper.getUserId();
        List<EntityMap> groupList = listByUserIdAndGroupShop(data, userId, null, null);
        EntityMap extra = resultBody.getExtra();
        //合计金额
        EntityMap map = totalShopCard(userId, CommonConstants.ENABLED);
        Integer selectedNum = map.getInt("selectedNum", 0);
        if (selectedNum.equals(data.size())) {
            map.put("selectAll", 1);
        } else {
            map.put("selectAll", 0);
        }
        result.put("groupList", groupList);
        result.putAll(map);
        result.putAll(extra);
        return ResultBody.ok(result);
    }

    /**
     * 查询个人购物车已选商品(按店铺分组)
     *
     * @param userId
     * @return
     */
    @Override
    public List<EntityMap> listByUserIdAndGroupShop(Long userId, String couponUserIds) {
        List<EntityMap> data = listByUserId(userId);
        return listByUserIdAndGroupShop(data, userId, couponUserIds, CommonConstants.ENABLED);
    }

    /**
     * 查询订单结算时优惠券列表
     *
     * @param userId
     * @return
     */
    @Override
    public EntityMap selectCouponList(Long userId) {
        List<EntityMap> data = listByUserIdAndGroupShop(userId, null);
        return couponUserService.listByShopCard(userId, data);
    }

    /**
     * 删除用户购物车中已生成订单的商品
     *
     * @param orderDetailsList
     * @return
     */
    @Override
    public Boolean clearByOrderDetails(List<OrderDetails> orderDetailsList, Long userId) {
        if (FlymeUtils.isNotEmpty(orderDetailsList)) {
            List<Long> skuIds = new ArrayList<>();
            for (OrderDetails orderDetails : orderDetailsList) {
                Long skuId = orderDetails.getSkuId();
                skuIds.add(skuId);
            }
            if (FlymeUtils.allNotNull(skuIds, userId)) {
                CriteriaDelete cd = new CriteriaDelete();
                cd.in("skuId", skuIds);
                cd.eq("userId", userId);
                return remove(cd);
            }
        }
        return false;
    }

    /**
     * 查询个人购物车已选商品
     *
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public List<EntityMap> listByUserId(Long userId) {
        CriteriaQuery cq = new CriteriaQuery(OrderShopcart.class);
        cq.select(OrderShopcart.class, "*");
        cq.eq(OrderShopcart.class, "userId", userId);
        cq.eq(OrderShopcart.class, "selected", CommonConstants.ENABLED);
        cq.select(ProdSku.class, "skuId", "title", "skuTitle", "images", "indexes", "price", "num", "productNo");
        cq.select(ProdShop.class, "shopName", "companyId");
        cq.select(ProdProduct.class, "coverImage", "freight","categoryId1","categoryId2","categoryId3");
        cq.createJoin(ProdSku.class);
        cq.createJoin(ProdShop.class);
        cq.createJoin(ProdProduct.class);
        return selectEntityMap(cq);
    }


    /**
     * 添加购物车
     *
     * @param params
     * @return
     */
    @Override
    public ResultBody addShopCart(Map<String, Object> params) {
        CriteriaSave cs = new CriteriaSave(params, OrderShopcart.class);
        Long skuId = cs.getLong("skuId");
        //操作类型 1 加 2减 3 设置
        Integer optType = cs.getInt("optType", 1);
        Integer num = cs.getInt("num", 1);
        ApiAssert.isNotEmpty("商品不能为空", skuId);
        ApiAssert.gtzero("最少购买1件哦!", num);
        //查询商品规格
        ProdSku sku = skuService.getById(skuId);
        ApiAssert.isNotEmpty("所选规格不存在", sku);
        Integer enable = sku.getEnable();
        ApiAssert.eq("所选规格已下架", enable, CommonConstants.ENABLED);
        ProdProduct prodProduct = productService.getById(sku.getProductId());
        ApiAssert.isNotEmpty("商品不存在", prodProduct);
        Integer onlineState = prodProduct.getOnLineState();
        ApiAssert.eq("商品已下架", onlineState, CommonConstants.ENABLED);
        return addShopCart(prodProduct, sku, num, optType);
    }

    /**
     * 查询购车明细
     *
     * @param userId
     * @param skuId
     * @return
     */
    @Override
    public OrderShopcart findByUserIdAndSkuId(Long userId, Long skuId) {
        CriteriaQuery cq = new CriteriaQuery(OrderShopcart.class);
        cq.eq(true, "userId", userId);
        cq.eq(true, "skuId", skuId);
        return getOne(cq);
    }

    /**
     * 删除购物车
     *
     * @param cd
     * @return
     */
    @Override
    public ResultBody beforeDelete(CriteriaDelete<OrderShopcart> cd) {
        Long userId = OpenHelper.getUserId();
        cd.eq("userId", userId);
        return ResultBody.ok();
    }


    /**
     * 清空购物车
     *
     * @param userId
     * @return
     */
    @Override
    public ResultBody clearAll(Long userId) {
        CriteriaDelete cd = new CriteriaDelete();
        cd.eq(true, "userId", userId);
        Boolean del = remove(cd);
        if (del) {
            EntityMap map = new EntityMap();
            map.put("totalAmount", 0);
            return ResultBody.ok("删除成功", map);
        } else {
            return ResultBody.failed("删除失败");
        }
    }

    /**
     * 全选购物车
     *
     * @param userId
     * @param selected
     * @return
     */
    @Override
    public ResultBody checkAll(Long userId, Integer selected) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "selected", selected);
        cu.eq(true, "userId", userId);
        Boolean update = update(cu);
        if (update) {
            //合计金额
            EntityMap map = totalShopCard(userId, CommonConstants.ENABLED);
            return ResultBody.ok(map);
        } else {
            return ResultBody.failed("操作失败");
        }
    }

    /**
     * 全选购物车内单个店铺所有商品
     *
     * @param userId
     * @param shopId
     * @param selected
     * @return
     */
    @Override
    public ResultBody checkByShopId(Long userId, Long shopId, Integer selected) {
        CriteriaUpdate<OrderShopcart> cu = new CriteriaUpdate();
        cu.set(true, "selected", selected);
        cu.eq(true, "shopId", shopId);
        cu.eq(true, "userId", userId);
        Boolean update = update(cu);
        if (update) {
            //合计金额
            EntityMap map = totalShopCard(userId, CommonConstants.ENABLED);
            return ResultBody.ok(map);
        } else {
            return ResultBody.failed("操作失败");
        }
    }

    /**
     * 选择购物车单个商品
     *
     * @param userId
     * @param shopCardId
     * @return
     */
    @Override
    public ResultBody checkByShopCardId(Long userId, Long shopCardId) {
        OrderShopcart orderShopcart = getById(shopCardId);
        Integer selected = orderShopcart.getSelected();
        orderShopcart.setSelected(Math.abs(selected - 1));
        Boolean update = updateById(orderShopcart);
        if (update) {
            //合计金额
            EntityMap map = totalShopCard(userId, CommonConstants.ENABLED);
            return ResultBody.ok(map);
        } else {
            return ResultBody.failed("操作失败");
        }
    }


    /**
     * 更新购车商品所选规格
     *
     * @param shopCardId
     * @param skuId
     * @param num
     * @return
     */
    @Override
    public ResultBody updateSku(Long shopCardId, Long skuId, Integer num) {
        ApiAssert.isNotEmpty("商品Id不能为空", shopCardId);
        ApiAssert.isNotEmpty("规格不能为空", skuId);
        num = FlymeUtils.getInteger(num, 1);
        ApiAssert.gtzero("最少购买1件哦!", num);
        Long userId = OpenHelper.getUserId();
        OrderShopcart orderShopcarts = selectByUserIdAndSkuId(userId, skuId, shopCardId);
        OrderShopcart update = getById(shopCardId);
        if (FlymeUtils.isNotEmpty(orderShopcarts)) {
            Integer buyNum = orderShopcarts.getBuyNum();
            ApiAssert.isNotEmpty("商品不存在", update);
            update.setBuyNum(num + buyNum);
            removeById(orderShopcarts.getShopCardId());
        } else {
            update.setBuyNum(num);
        }
        update.setSkuId(skuId);
        boolean tag = updateById(update);
        if (tag) {
            return ResultBody.ok();
        } else {
            return ResultBody.failed("更新失败");
        }
    }

    private OrderShopcart selectByUserIdAndSkuId(Long userId, Long skuId, Long shopCardId) {
        CriteriaQuery cq = new CriteriaQuery(OrderShopcart.class);
        cq.eq(true, "userId", userId);
        cq.eq(true, "skuId", skuId);
        cq.ne(true, "shopCardId", shopCardId);
        return getOne(cq);
    }

    /**
     * 删除购车所选商品
     *
     * @param cd
     * @param ids
     * @return
     */
    @Override
    public ResultBody afterDelete(CriteriaDelete cd, Serializable[] ids) {
        Long userId = OpenHelper.getUserId();
        //EntityMap map = totalShopCard(userId, CommonConstants.ENABLED);
        return ResultBody.ok("删除成功");
    }

    /**
     * 查询购物车店铺ID
     *
     * @param userId
     * @return
     */
    private List<Long> selectShopId(Long userId, Integer selected) {
        CriteriaQuery<OrderShopcart> cq = new CriteriaQuery(OrderShopcart.class);
        cq.select("shopId");
        cq.eq(true, "userId", userId);
        if (FlymeUtils.isNotEmpty(selected)) {
            cq.eq(true, "selected", selected);
        }
        cq.groupBy("shopId");
        return listObjs(cq, e -> Long.parseLong(e.toString()));
    }


    /**
     * 添加购物车业务逻辑
     *
     * @param prodProduct
     * @param sku
     * @param buyNum
     * @return
     */
    private ResultBody addShopCart(ProdProduct prodProduct, ProdSku sku, Integer buyNum, Integer optType) {
        Long skuId = sku.getSkuId();
        //加锁避免并发问题
        RLock lock = redisLock.lock(skuId);
        try {
            Long userId = OpenHelper.getUserId();
            //最低1个
            buyNum = FlymeUtils.getInteger(buyNum, 1);
            ApiAssert.isTrue("库存不足", (sku.getNum() >= buyNum) || sku.getNum().equals(-1));
            OrderShopcart orderShopcart = findByUserIdAndSkuId(userId, skuId);
            Integer oldNum = 0;
            Boolean insert = false;
            if (FlymeUtils.isEmpty(orderShopcart)) {
                orderShopcart = new OrderShopcart();
                orderShopcart.setSkuId(skuId);
                orderShopcart.setShopId(prodProduct.getShopId());
                orderShopcart.setProductId(prodProduct.getProductId());
                orderShopcart.setUserId(userId);
                orderShopcart.setSelected(CommonConstants.ENABLED);
                insert = true;
            } else {
                oldNum = orderShopcart.getBuyNum();
            }
            if (optType.equals(3)) {
                orderShopcart.setBuyNum(buyNum + oldNum);
            } else {
                orderShopcart.setBuyNum(buyNum);
            }
            if (insert) {
                save(orderShopcart);
            } else {
                updateById(orderShopcart);
            }
            //合计金额
            EntityMap map = totalShopCard(userId, CommonConstants.ENABLED);
            return ResultBody.ok(map);
        } finally {
            redisLock.unlock(lock);
        }

    }

    /**
     * 计算购物车合计金额
     */
    @Override
    public EntityMap totalShopCard(Long userId, Integer selected) {
        CriteriaQuery cq = new CriteriaQuery(OrderShopcart.class);
        cq.select("sum(sku.price*shopcart.buyNum) totalAmount,sum(shopcart.buyNum) totalNum,sum(sku.freight) totalFreight,sum(shopcart.selected) selectedNum");
        cq.eq(true, "userId", userId);
        cq.eq(FlymeUtils.isNotEmpty(selected), "selected", selected);
        cq.createJoin(ProdSku.class).setMainField("skuId").setJoinField("skuId");
        cq.groupBy("userId");
        EntityMap result = findOne(cq);
        BigDecimal totalAmount = result.getBigDecimal("totalAmount");
        Integer totalNum = result.getInt("totalNum", 0);
        Integer selectedNum = result.getInt("selectedNum", 0);
        result.put("totalAmount", totalAmount);
        result.put("selectedNum", selectedNum);
        result.put("totalNum", totalNum);
        return result;
    }


    /**
     * 对个人购车进行分组(按店铺分组,不同店铺商品进行拆单)
     *
     * @param data          商品数据
     * @param userId        用户ID
     * @param couponUserIds 优惠券ID
     * @return
     */
    private List<EntityMap> listByUserIdAndGroupShop(List<EntityMap> data, Long userId, String couponUserIds, Integer selected) {
        List<Long> shopIds = selectShopId(userId, selected);
        List<EntityMap> groupList = new ArrayList<>();

        for (Long shopId : shopIds) {
            List<EntityMap> shopCardList = new ArrayList<>();
            EntityMap groupDetails = new EntityMap();
            BigDecimal totalAmount = new BigDecimal("0");
            BigDecimal shopTotalAmount = new BigDecimal("0");
            //店铺运费
            BigDecimal shopTotalFreight = new BigDecimal("0");

            Integer shopTotalNum = 0;
            //门店是否全选
            Integer shopSelectedNum = 0;
            for (EntityMap shopCard : data) {
                Long id = shopCard.getLong("shopId");
                if (shopId.equals(id)) {
                    String shopName = shopCard.get("shopName");
                    String images = shopCard.get("images");
                    if (FlymeUtils.isEmpty(images) || images.length() < 10) {
                        images = shopCard.get("coverImage");
                        shopCard.add("images", images);
                    }
                    Integer shopSelected = shopCard.getInt("selected", 0);
                    Long companyId = shopCard.get("companyId");

                    BigDecimal price = shopCard.getBigDecimal("price");
                    Integer buyNum = shopCard.getInt("buyNum", 0);
                    BigDecimal freight = shopCard.getBigDecimal("freight");
                    groupDetails.putIfAbsent("shopName", shopName);
                    groupDetails.putIfAbsent("companyId", companyId);
                    shopTotalAmount = shopTotalAmount.add(price.multiply(new BigDecimal(buyNum)));
                    shopTotalFreight = shopTotalFreight.add(freight);
                    shopTotalNum += buyNum;
                    if (shopSelected.equals(CommonConstants.ENABLED)) {
                        shopSelectedNum++;
                    }
                    shopCardList.add(shopCard);
                }

            }
            if (shopSelectedNum.equals(shopCardList.size())) {
                groupDetails.put("shopSelectAll", 1);
            } else {
                groupDetails.put("shopSelectAll", 0);
            }
            groupDetails.put("shopTotalAmount", shopTotalAmount);
            groupDetails.put("shopTotalNum", shopTotalNum);
            groupDetails.put("shopTotalFreight", shopTotalFreight);
            groupDetails.put("shopCardList", shopCardList);

            List<EntityMap> afterSale = aftersaleService.selectByCompanyId(shopId);
            groupDetails.put("afterService", afterSale);

            groupDetails.put("shopId", shopId);
            groupList.add(groupDetails);

        }
        return groupList;
    }


}
